package com.zyg.plugin;

import com.zyg.page.Page;
import com.zyg.utils.PluginUtils;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
import java.util.Properties;

@Intercepts(@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}))
public class MyPaginationInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 先判断是不是SELECT操作  (跳过存储过程)
        StatementHandler statementHandler = PluginUtils.realTarget(invocation.getTarget());
        //检查当前分页条件
        BoundSql boundSql = statementHandler.getBoundSql();
        Object parameterObject = boundSql.getParameterObject();
        Page page = null;
        if (parameterObject instanceof Page) {
            page = (Page) parameterObject;
        } else if (parameterObject instanceof Map) {
            page = (Page) ((Map) parameterObject).values().stream().filter(v -> v instanceof Page).findFirst().orElse(null);
        }
        /*
         * 不需要分页的场合，如果 size 小于 0 返回结果集
         */
        if (page == null|| page.getSize() < 0) {
            return invocation.proceed();
        }
        //1.设置总行数
        //select count(0) from (sql)
        page.setTotal(queryTotal(invocation));
        //2.修改原有sql
        //select * from student offset 0 limit 20
        String newSql = String.format("%s limit %s offset %s", boundSql.getSql(), page.getSize(),page.setOffSet());
        SystemMetaObject.forObject(boundSql).setValue("sql", newSql);
        return invocation.proceed();
    }

    private long queryTotal(Invocation invocation) throws SQLException {
        long count = 0;
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        String sql = String.format("select count(0) from (%s) as total", statementHandler.getBoundSql().getSql());
        Connection connection = (Connection) invocation.getArgs()[0];
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        statementHandler.getParameterHandler().setParameters(preparedStatement);
        ResultSet resultSet = preparedStatement.executeQuery();
        if (resultSet.next()) {
            count = resultSet.getLong(1);
        }
        return count;
    }

    @Override
    public Object plugin(Object target) {
        if (target instanceof StatementHandler) {
            return Plugin.wrap(target, this);
        }
        return target;
    }

    @Override
    public void setProperties(Properties properties) {

    }
}
